<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>关键字快速搜索</title>
<style>
body
{
	font-size: 14px;
}

h2
{
	display: inline;
	margin: 0;
}

#spnKeyNum, #spnWordNum
{
	color: #F00;
}

#spnList a
{
	font-size: 12px;
	color: #0000FF;
}

#spnTime
{
	color: #600;
}

textarea, #divDisplay
{
	margin: 0;
	padding: 0;
	font-size: 14px;
	display: block;
	background: #EEE;
	border: #999 solid 1px;
}

#txtKeys
{
	width: 95%;
	height: 100px;
}

#txtContent, #divDisplay
{
	height: 400px;
	width: 95%;
}

#divDisplay
{
	display: none;
	overflow: auto;
}

#divDisplay em
{
	color: #F00;
	font-style: normal;
}

#divFoot
{
	padding: 5px;
	width: 95%;
}

#spnLable2
{
	margin: 5px;
	float: left;
	color: #690;
}

button
{
	float: left;
}

#desc
{
	color: #333;
	float: right;
}
</style>
</head>

<body onload="handleLoad();">
<div id="divTop">
	<h2>关键字</h2>
	<span id="spnLable1">(<span id="spnKeyNum">0</span>个)</span>
	<span id="spnList">
		<a href="javascript:load('city.txt');">世界城市</a>
		<a href="javascript:load('words.txt');">部分英文单词</a>
		<a href="javascript:load('idiom.txt');">成语全集</a>
	</span>
</div>
<div id="divMain">
	<textarea id="txtKeys" onchange="handleKeyChange();"></textarea>
	<h2>内容</h2>
	<span id="spnLable1">(<span id="spnWordNum">0</span>字)</span>
	<textarea id="txtContent" onchange="handleContentChange();"></textarea>
	<div id="divDisplay"></div>
</div>
<div id="divFoot">
	<span id="spnLable2">搜索用时: <span id="spnTime">0</span>ms</span>
	<button id="btnStart" onclick="handleClick();"> 测试</button>
	<button id="btnReset" onclick="reset()" disabled="disabled"> 重置</button>
	<span id="desc">EtherDream 2009</span>
</div>

<script>
var tblRoot;

/*
 * 函数: makeTree
 * 注释: 将关键字生成一颗树
 */
function makeTree()
{
	var strKeys = objKeys.value;
	var arrKeys = strKeys.split("");
	var tblCur = tblRoot = {};
	var key;

	for(var i=0,n=arrKeys.length; i<n; i++)
	{
		key = arrKeys[i];

		if(key == ';')		//完成当前关键字
		{
			tblCur.end = true;
			tblCur = tblRoot;
			continue;
		}

		if(key in tblCur)	//生成子节点
			tblCur = tblCur[key];
		else
			tblCur = tblCur[key] = {};
	}

	tblCur.end = true;		//最后一个关键字没有分割符
}

/*
 * 函数: search
 * 注释: 标记出内容中关键字的位置
 */
function search(content)
{
	var tblCur;
	var i = 0;
	var n = content.length;
	var p, v;
	var arrMatch = [];

	while(i < n)
	{
		tblCur = tblRoot;
		p = i;
		v = 0;

		for(;;)
		{
			if(!(tblCur = tblCur[content.charAt(p++)]))
			{
				i++;
				break;
			}

			if(tblCur.end)		//找到匹配关键字
				v = p;
		}

		if(v)					//最大匹配
		{
			arrMatch.push(i-1, v);
			i = v;
		}
	}

	return arrMatch;
}
</script>

<script>
var $ = function(id){return document.getElementById(id)};

var objKeys = $("txtKeys");
var objContent = $("txtContent");
var objDisplay = $("divDisplay");
var bKeyChanged = false;


function handleKeyChange()
{
	var str = objKeys.value;
	var n;

	if(str.length==0)
		n = 0;
	else
		n = str.split(";").length;

	/*
	 * 显示关键字数量
	 */
	$("spnKeyNum").innerHTML = n;

	bKeyChanged = true;
}

function handleContentChange()
{
	/*
	 * 显示内容长度
	 */
	$("spnWordNum").innerHTML = objContent.value.length;
}

function handleLoad()
{
	handleKeyChange();
	handleContentChange();
}

function handleClick()
{
	var strContent = objContent.value;
	var arrMatch;
	var arrHTML = [];
	var strHTML;
	var mid;
	var p = 0;


	$("btnStart").disabled = true;
	$("btnReset").disabled = false;

	if(bKeyChanged)
	{
		makeTree();
		bKeyChanged = false;
	}

	/*
	 * 开始搜索! 
	 */
	var t = +new Date();

	arrMatch = search(strContent);

	/*
	 * 搜索用时
	 */
	$("spnTime").innerHTML = +new Date() - t;

	/*
	 * 标记关键字
	 */
	for(var i=0,n=arrMatch.length; i<n; i+=2)
	{
		mid = arrMatch[i];
		arrHTML.push(strContent.substring(p, mid),
					 "<em>",
					 strContent.substring(mid, p = arrMatch[i+1]),
					 "</em>");
	}
	arrHTML.push(strContent.substring(p));

	strHTML = arrHTML.join("").replace(/\n/g, "<br>");

	/*
	 * 显示结果
	 */
	objDisplay.innerHTML = strHTML;

	objContent.style.display = "none";
	objDisplay.style.display = "block";
}

function reset()
{
	$("btnStart").disabled = false;
	$("btnReset").disabled = true;

	objContent.style.display = "block";
	objDisplay.style.display = "none";
}

function load(file)
{
	/*
	 * 创建HTTP组件
	 */
	if(window.ActiveXObject)
	{
		objHttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	else
	{
		objHttp = new XMLHttpRequest();
		objHttp.overrideMimeType("text/xml");
	}

	objHttp.onreadystatechange = function()
	{
		if(objHttp.readyState != 4)
			return;

		objKeys.value = objHttp.responseText;
		handleKeyChange();
	};

	/*
	 * 发送请求
	 */
	objHttp.open("GET", file, true);
	objHttp.send(null);
}

</script>
</body>
</html>
